home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 008a / perl40_2.zip / DOIO.C < prev    next >
C/C++ Source or Header  |  1991-12-19  |  63KB  |  3,053 lines

  1. /* $RCSfile: doio.c,v $$Revision: 4.0.1.4 $$Date: 91/11/05 16:51:43 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    doio.c,v $
  9.  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
  10.  * patch11: prepared for ctype implementations that don't define isascii()
  11.  * patch11: perl mistook some streams for sockets because they return mode 0 too
  12.  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
  13.  * patch11: certain perl errors should set EBADF so that $! looks better
  14.  * patch11: truncate on a closed filehandle could dump
  15.  * patch11: stats of _ forgot whether prior stat was actually lstat
  16.  * patch11: -T returned true on NFS directory
  17.  *
  18.  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
  19.  * patch10: read didn't work from character special files open for writing
  20.  * patch10: close-on-exec wrongly set on system file descriptors
  21.  *
  22.  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
  23.  * patch4: new copyright notice
  24.  * patch4: system fd's are now treated specially
  25.  * patch4: added $^F variable to specify maximum system fd, default 2
  26.  * patch4: character special files now opened with bidirectional stdio buffers
  27.  * patch4: taintchecks could improperly modify parent in vfork()
  28.  * patch4: many, many itty-bitty portability fixes
  29.  *
  30.  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
  31.  * patch1: hopefully straightened out some of the Xenix mess
  32.  *
  33.  * Revision 4.0  91/03/20  01:07:06  lwall
  34.  * 4.0 baseline.
  35.  *
  36.  */
  37.  
  38.  
  39. #include "EXTERN.h"
  40. #include "perl.h"
  41.  
  42.  
  43. #ifdef HAS_SOCKET
  44. #include <sys/socket.h>
  45. #include <netdb.h>
  46. #endif
  47.  
  48.  
  49. #ifdef HAS_SELECT
  50. #ifdef I_SYS_SELECT
  51. #ifndef I_SYS_TIME
  52. #include <sys/select.h>
  53. #endif
  54. #endif
  55. #endif
  56.  
  57.  
  58. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  59. #include <sys/ipc.h>
  60. #ifdef HAS_MSG
  61. #include <sys/msg.h>
  62. #endif
  63. #ifdef HAS_SEM
  64. #include <sys/sem.h>
  65. #endif
  66. #ifdef HAS_SHM
  67. #include <sys/shm.h>
  68. #endif
  69. #endif
  70.  
  71.  
  72. #ifdef I_PWD
  73. #include <pwd.h>
  74. #endif
  75. #ifdef I_GRP
  76. #include <grp.h>
  77. #endif
  78. #ifdef I_UTIME
  79. #include <utime.h>
  80. #endif
  81. #ifdef I_FCNTL
  82. #include <fcntl.h>
  83. #endif
  84. #ifdef I_SYS_FILE
  85. #include <sys/file.h>
  86. #endif
  87.  
  88.  
  89.  
  90. int laststatval = -1;
  91. int laststype = O_STAT;
  92.  
  93.  
  94. bool
  95. do_open(stab,name,len)
  96. STAB *stab;
  97. register char *name;
  98. int len;
  99. {
  100.     FILE *fp;
  101.     register STIO *stio = stab_io(stab);
  102.     char *myname = savestr(name);
  103.     int result;
  104.     int fd;
  105.     int writing = 0;
  106.     char mode[3];        /* stdio file mode ("r\0" or "r+\0") */
  107.     FILE *saveifp = Nullfp;
  108.     FILE *saveofp = Nullfp;
  109.     char savetype = ' ';
  110.  
  111.  
  112.     name = myname;
  113.     forkprocess = 1;        /* assume true if no fork */
  114.     while (len && isSPACE(name[len-1]))
  115.     name[--len] = '\0';
  116.     if (!stio)
  117.     stio = stab_io(stab) = stio_new();
  118.     else if (stio->ifp) {
  119.     fd = fileno(stio->ifp);
  120.     if (stio->type == '-')
  121.         result = 0;
  122.     else if (fd <= maxsysfd) {
  123.         saveifp = stio->ifp;
  124.         saveofp = stio->ofp;
  125.         savetype = stio->type;
  126.         result = 0;
  127.     }
  128.     else if (stio->type == '|')
  129.         result = mypclose(stio->ifp);
  130.     else if (stio->ifp != stio->ofp) {
  131.         if (stio->ofp) {
  132.         result = fclose(stio->ofp);
  133.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  134.         }
  135.         else
  136.         result = fclose(stio->ifp);
  137.     }
  138.     else
  139.         result = fclose(stio->ifp);
  140.     if (result == EOF && fd > maxsysfd)
  141.         fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  142.           stab_name(stab));
  143.     stio->ofp = stio->ifp = Nullfp;
  144.     }
  145.     if (*name == '+' && len > 1 && name[len-1] != '|') {    /* scary */
  146.     mode[1] = *name++;
  147.     mode[2] = '\0';
  148.     --len;
  149.     writing = 1;
  150.     }
  151.     else  {
  152.     mode[1] = '\0';
  153.     }
  154.     stio->type = *name;
  155.     if (*name == '|') {
  156.     /*SUPPRESS 530*/
  157.     for (name++; isSPACE(*name); name++) ;
  158. #ifdef TAINT
  159.     taintenv();
  160.     taintproper("Insecure dependency in piped open");
  161. #endif
  162.     fp = mypopen(name,"w");
  163.     writing = 1;
  164.     }
  165.     else if (*name == '>') {
  166. #ifdef TAINT
  167.     taintproper("Insecure dependency in open");
  168. #endif
  169.     name++;
  170.     if (*name == '>') {
  171.         mode[0] = stio->type = 'a';
  172.         name++;
  173.     }
  174.     else
  175.         mode[0] = 'w';
  176.     writing = 1;
  177.     if (*name == '&') {
  178.       duplicity:
  179.         name++;
  180.         while (isSPACE(*name))
  181.         name++;
  182.         if (isDIGIT(*name))
  183.         fd = atoi(name);
  184.         else {
  185.         stab = stabent(name,FALSE);
  186.         if (!stab || !stab_io(stab)) {
  187. #ifdef EINVAL
  188.             errno = EINVAL;
  189. #endif
  190.             goto say_false;
  191.         }
  192.         if (stab_io(stab) && stab_io(stab)->ifp) {
  193.             fd = fileno(stab_io(stab)->ifp);
  194.             if (stab_io(stab)->type == 's')
  195.             stio->type = 's';
  196.         }
  197.         else
  198.             fd = -1;
  199.         }
  200.         if (!(fp = fdopen(fd = dup(fd),mode))) {
  201.         close(fd);
  202.         }
  203.     }
  204.     else {
  205.         while (isSPACE(*name))
  206.         name++;
  207.         if (strEQ(name,"-")) {
  208.         fp = stdout;
  209.         stio->type = '-';
  210.         }
  211.         else  {
  212.         fp = fopen(name,mode);
  213.         }
  214.     }
  215.     }
  216.     else {
  217.     if (*name == '<') {
  218.         mode[0] = 'r';
  219.         name++;
  220.         while (isSPACE(*name))
  221.         name++;
  222.         if (*name == '&')
  223.         goto duplicity;
  224.         if (strEQ(name,"-")) {
  225.         fp = stdin;
  226.         stio->type = '-';
  227.         }
  228.         else
  229.         fp = fopen(name,mode);
  230.     }
  231.     else if (name[len-1] == '|') {
  232. #ifdef TAINT
  233.         taintenv();
  234.         taintproper("Insecure dependency in piped open");
  235. #endif
  236.         name[--len] = '\0';
  237.         while (len && isSPACE(name[len-1]))
  238.         name[--len] = '\0';
  239.         /*SUPPRESS 530*/
  240.         for (; isSPACE(*name); name++) ;
  241.         fp = mypopen(name,"r");
  242.         stio->type = '|';
  243.     }
  244.     else {
  245.         stio->type = '<';
  246.         /*SUPPRESS 530*/
  247.         for (; isSPACE(*name); name++) ;
  248.         if (strEQ(name,"-")) {
  249.         fp = stdin;
  250.         stio->type = '-';
  251.         }
  252.         else
  253.         fp = fopen(name,"r");
  254.     }
  255.     }
  256.     Safefree(myname);
  257.     if (!fp)
  258.     goto say_false;
  259.     if (stio->type &&
  260.       stio->type != '|' && stio->type != '-') {
  261.     if (fstat(fileno(fp),&statbuf) < 0) {
  262.         (void)fclose(fp);
  263.         goto say_false;
  264.     }
  265.     if (S_ISSOCK(statbuf.st_mode))
  266.         stio->type = 's';    /* in case a socket was passed in to us */
  267. #ifdef HAS_SOCKET
  268.     else if (
  269. #ifdef S_IFMT
  270.         !(statbuf.st_mode & S_IFMT)
  271. #else
  272.         !statbuf.st_mode
  273. #endif
  274.     ) {
  275.         if (getsockname(fileno(fp), tokenbuf, 0) >= 0 || errno != ENOTSOCK)
  276.         stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
  277.                 /* but some return 0 for streams too, sigh */
  278.     }
  279. #endif
  280.     }
  281.     if (saveifp) {        /* must use old fp? */
  282.     fd = fileno(saveifp);
  283.     if (saveofp) {
  284.         fflush(saveofp);        /* emulate fclose() */
  285.         if (saveofp != saveifp) {    /* was a socket? */
  286.         fclose(saveofp);
  287.         if (fd > 2)
  288.             Safefree(saveofp);
  289.         }
  290.     }
  291.     if (fd != fileno(fp)) {
  292.         dup2(fileno(fp), fd);
  293.         fclose(fp);
  294.     }
  295.     fp = saveifp;
  296.     }
  297. #if defined(HAS_FCNTL) && defined(F_SETFD)
  298.     fd = fileno(fp);
  299.     fcntl(fd,F_SETFD,fd > maxsysfd);
  300. #endif
  301.     stio->ifp = fp;
  302.     if (writing) {
  303.     if (stio->type == 's'
  304.       || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
  305.         if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
  306.         fclose(fp);
  307.         stio->ifp = Nullfp;
  308.         goto say_false;
  309.         }
  310.     }
  311.     else
  312.         stio->ofp = fp;
  313.     }
  314.     return TRUE;
  315.  
  316.  
  317. say_false:
  318.     stio->ifp = saveifp;
  319.     stio->ofp = saveofp;
  320.     stio->type = savetype;
  321.     return FALSE;
  322. }
  323.  
  324.  
  325. FILE *
  326. nextargv(stab)
  327. register STAB *stab;
  328. {
  329.     register STR *str;
  330. #ifndef FLEXFILENAMES
  331.     int filedev;
  332.     int fileino;
  333. #endif
  334.     int fileuid;
  335.     int filegid;
  336.     static int filemode = 0;
  337.     static int lastfd;
  338.     static char *oldname;
  339.  
  340.  
  341.     if (!argvoutstab)
  342.     argvoutstab = stabent("ARGVOUT",TRUE);
  343.     if (filemode & (S_ISUID|S_ISGID)) {
  344.     fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
  345. #ifdef HAS_FCHMOD
  346.     (void)fchmod(lastfd,filemode);
  347. #else
  348.     (void)chmod(oldname,filemode);
  349. #endif
  350.     }
  351.     filemode = 0;
  352.     while (alen(stab_xarray(stab)) >= 0) {
  353.     str = ashift(stab_xarray(stab));
  354.     str_sset(stab_val(stab),str);
  355.     STABSET(stab_val(stab));
  356.     oldname = str_get(stab_val(stab));
  357.     if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
  358.         if (inplace) {
  359. #ifdef TAINT
  360.         taintproper("Insecure dependency in inplace open");
  361. #endif
  362.         if (strEQ(oldname,"-")) {
  363.             str_free(str);
  364.             defoutstab = stabent("STDOUT",TRUE);
  365.             return stab_io(stab)->ifp;
  366.         }
  367. #ifndef FLEXFILENAMES
  368.         filedev = statbuf.st_dev;
  369.         fileino = statbuf.st_ino;
  370. #endif
  371.         filemode = statbuf.st_mode;
  372.         fileuid = statbuf.st_uid;
  373.         filegid = statbuf.st_gid;
  374.         if (!S_ISREG(filemode)) {
  375.             warn("Can't do inplace edit: %s is not a regular file",
  376.               oldname );
  377.             do_close(stab,FALSE);
  378.             str_free(str);
  379.             continue;
  380.         }
  381.         if (*inplace) {
  382. #ifdef SUFFIX
  383.             add_suffix(str,inplace);
  384. #else
  385.             str_cat(str,inplace);
  386. #endif
  387. #ifndef FLEXFILENAMES
  388.             if (stat(str->str_ptr,&statbuf) >= 0
  389.               && statbuf.st_dev == filedev
  390.               && statbuf.st_ino == fileino ) {
  391.             warn("Can't do inplace edit: %s > 14 characters",
  392.               str->str_ptr );
  393.             do_close(stab,FALSE);
  394.             str_free(str);
  395.             continue;
  396.             }
  397. #endif
  398. #ifdef HAS_RENAME
  399. #ifndef MSDOS
  400.             if (rename(oldname,str->str_ptr) < 0) {
  401.             warn("Can't rename %s to %s: %s, skipping file",
  402.               oldname, str->str_ptr, strerror(errno) );
  403.             do_close(stab,FALSE);
  404.             str_free(str);
  405.             continue;
  406.             }
  407. #else
  408.             do_close(stab,FALSE);
  409.             (void)unlink(str->str_ptr);
  410.             (void)rename(oldname,str->str_ptr);
  411.             do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
  412. #endif /* MSDOS */
  413. #else
  414.             (void)UNLINK(str->str_ptr);
  415.             if (link(oldname,str->str_ptr) < 0) {
  416.             warn("Can't rename %s to %s: %s, skipping file",
  417.               oldname, str->str_ptr, strerror(errno) );
  418.             do_close(stab,FALSE);
  419.             str_free(str);
  420.             continue;
  421.             }
  422.             (void)UNLINK(oldname);
  423. #endif
  424.         }
  425.         else {
  426. #ifndef MSDOS
  427.             if (UNLINK(oldname) < 0) {
  428.             warn("Can't rename %s to %s: %s, skipping file",
  429.               oldname, str->str_ptr, strerror(errno) );
  430.             do_close(stab,FALSE);
  431.             str_free(str);
  432.             continue;
  433.             }
  434. #else
  435.             fatal("Can't do inplace edit without backup");
  436. #endif
  437.         }
  438.  
  439.  
  440.         str_nset(str,">",1);
  441.         str_cat(str,oldname);
  442.         errno = 0;        /* in case sprintf set errno */
  443.         if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
  444.             warn("Can't do inplace edit on %s: %s",
  445.               oldname, strerror(errno) );
  446.             do_close(stab,FALSE);
  447.             str_free(str);
  448.             continue;
  449.         }
  450.         defoutstab = argvoutstab;
  451.         lastfd = fileno(stab_io(argvoutstab)->ifp);
  452.         (void)fstat(lastfd,&statbuf);
  453. #ifdef HAS_FCHMOD
  454.         (void)fchmod(lastfd,filemode);
  455. #else
  456.         (void)chmod(oldname,filemode);
  457. #endif
  458.         if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
  459. #ifdef HAS_FCHOWN
  460.             (void)fchown(lastfd,fileuid,filegid);
  461. #else
  462. #ifdef HAS_CHOWN
  463.             (void)chown(oldname,fileuid,filegid);
  464. #endif
  465. #endif
  466.         }
  467.         }
  468.         str_free(str);
  469.         return stab_io(stab)->ifp;
  470.     }
  471.     else
  472.         fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
  473.     str_free(str);
  474.     }
  475.     if (inplace) {
  476.     (void)do_close(argvoutstab,FALSE);
  477.     defoutstab = stabent("STDOUT",TRUE);
  478.     }
  479.     return Nullfp;
  480. }
  481.  
  482.  
  483. #ifdef HAS_PIPE
  484. void
  485. do_pipe(str, rstab, wstab)
  486. STR *str;
  487. STAB *rstab;
  488. STAB *wstab;
  489. {
  490.     register STIO *rstio;
  491.     register STIO *wstio;
  492.     int fd[2];
  493.  
  494.  
  495.     if (!rstab)
  496.     goto badexit;
  497.     if (!wstab)
  498.     goto badexit;
  499.  
  500.  
  501.     rstio = stab_io(rstab);
  502.     wstio = stab_io(wstab);
  503.  
  504.  
  505.     if (!rstio)
  506.     rstio = stab_io(rstab) = stio_new();
  507.     else if (rstio->ifp)
  508.     do_close(rstab,FALSE);
  509.     if (!wstio)
  510.     wstio = stab_io(wstab) = stio_new();
  511.     else if (wstio->ifp)
  512.     do_close(wstab,FALSE);
  513.  
  514.  
  515.     if (pipe(fd) < 0)
  516.     goto badexit;
  517.     rstio->ifp = fdopen(fd[0], "r");
  518.     wstio->ofp = fdopen(fd[1], "w");
  519.     wstio->ifp = wstio->ofp;
  520.     rstio->type = '<';
  521.     wstio->type = '>';
  522.     if (!rstio->ifp || !wstio->ofp) {
  523.     if (rstio->ifp) fclose(rstio->ifp);
  524.     else close(fd[0]);
  525.     if (wstio->ofp) fclose(wstio->ofp);
  526.     else close(fd[1]);
  527.     goto badexit;
  528.     }
  529.  
  530.  
  531.     str_sset(str,&str_yes);
  532.     return;
  533.  
  534.  
  535. badexit:
  536.     str_sset(str,&str_undef);
  537.     return;
  538. }
  539. #endif
  540.  
  541.  
  542. bool
  543. do_close(stab,explicit)
  544. STAB *stab;
  545. bool explicit;
  546. {
  547.     bool retval = FALSE;
  548.     register STIO *stio;
  549.     int status;
  550.  
  551.  
  552.     if (!stab)
  553.     stab = argvstab;
  554.     if (!stab) {
  555.     errno = EBADF;
  556.     return FALSE;
  557.     }
  558.     stio = stab_io(stab);
  559.     if (!stio) {        /* never opened */
  560.     if (dowarn && explicit)
  561.         warn("Close on unopened file <%s>",stab_name(stab));
  562.     return FALSE;
  563.     }
  564.     if (stio->ifp) {
  565.     if (stio->type == '|') {
  566.         status = mypclose(stio->ifp);
  567.         retval = (status == 0);
  568.         statusvalue = (unsigned short)status & 0xffff;
  569.     }
  570.     else if (stio->type == '-')
  571.         retval = TRUE;
  572.     else {
  573.         if (stio->ofp && stio->ofp != stio->ifp) {        /* a socket */
  574.         retval = (fclose(stio->ofp) != EOF);
  575.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  576.         }
  577.         else
  578.         retval = (fclose(stio->ifp) != EOF);
  579.     }
  580.     stio->ofp = stio->ifp = Nullfp;
  581.     }
  582.     if (explicit)
  583.     stio->lines = 0;
  584.     stio->type = ' ';
  585.     return retval;
  586. }
  587.  
  588.  
  589. bool
  590. do_eof(stab)
  591. STAB *stab;
  592. {
  593.     register STIO *stio;
  594.     int ch;
  595.  
  596.  
  597.     if (!stab) {            /* eof() */
  598.     if (argvstab)
  599.         stio = stab_io(argvstab);
  600.     else
  601.         return TRUE;
  602.     }
  603.     else
  604.     stio = stab_io(stab);
  605.  
  606.  
  607.     if (!stio)
  608.     return TRUE;
  609.  
  610.  
  611.     while (stio->ifp) {
  612.  
  613.  
  614. #ifdef STDSTDIO            /* (the code works without this) */
  615.     if (stio->ifp->_cnt > 0)    /* cheat a little, since */
  616.         return FALSE;        /* this is the most usual case */
  617. #endif
  618.  
  619.  
  620.     ch = getc(stio->ifp);
  621.     if (ch != EOF) {
  622.         (void)ungetc(ch, stio->ifp);
  623.         return FALSE;
  624.     }
  625. #ifdef STDSTDIO
  626.     if (stio->ifp->_cnt < -1)
  627.         stio->ifp->_cnt = -1;
  628. #endif
  629.     if (!stab) {            /* not necessarily a real EOF yet? */
  630.         if (!nextargv(argvstab))    /* get another fp handy */
  631.         return TRUE;
  632.     }
  633.     else
  634.         return TRUE;        /* normal fp, definitely end of file */
  635.     }
  636.     return TRUE;
  637. }
  638.  
  639.  
  640. long
  641. do_tell(stab)
  642. STAB *stab;
  643. {
  644.     register STIO *stio;
  645.  
  646.  
  647.     if (!stab)
  648.     goto phooey;
  649.  
  650.  
  651.     stio = stab_io(stab);
  652.     if (!stio || !stio->ifp)
  653.     goto phooey;
  654.  
  655.  
  656.     if (feof(stio->ifp))
  657.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  658.  
  659.  
  660.     return ftell(stio->ifp);
  661.  
  662.  
  663. phooey:
  664.     if (dowarn)
  665.     warn("tell() on unopened file");
  666.     errno = EBADF;
  667.     return -1L;
  668. }
  669.  
  670.  
  671. bool
  672. do_seek(stab, pos, whence)
  673. STAB *stab;
  674. long pos;
  675. int whence;
  676. {
  677.     register STIO *stio;
  678.  
  679.  
  680.     if (!stab)
  681.     goto nuts;
  682.  
  683.  
  684.     stio = stab_io(stab);
  685.     if (!stio || !stio->ifp)
  686.     goto nuts;
  687.  
  688.  
  689.     if (feof(stio->ifp))
  690.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  691.  
  692.  
  693.     return fseek(stio->ifp, pos, whence) >= 0;
  694.  
  695.  
  696. nuts:
  697.     if (dowarn)
  698.     warn("seek() on unopened file");
  699.     errno = EBADF;
  700.     return FALSE;
  701. }
  702.  
  703.  
  704. int
  705. do_ctl(optype,stab,func,argstr)
  706. int optype;
  707. STAB *stab;
  708. int func;
  709. STR *argstr;
  710. {
  711.     register STIO *stio;
  712.     register char *s;
  713.     int retval;
  714.  
  715.  
  716.     if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
  717.     errno = EBADF;    /* well, sort of... */
  718.     return -1;
  719.     }
  720.  
  721.  
  722.     if (argstr->str_pok || !argstr->str_nok) {
  723.     if (!argstr->str_pok)
  724.         s = str_get(argstr);
  725.  
  726.  
  727. #ifdef IOCPARM_MASK
  728. #ifndef IOCPARM_LEN
  729. #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
  730. #endif
  731. #endif
  732. #ifdef IOCPARM_LEN
  733.     retval = IOCPARM_LEN(func);    /* on BSDish systes we're safe */
  734. #else
  735.     retval = 256;            /* otherwise guess at what's safe */
  736. #endif
  737.     if (argstr->str_cur < retval) {
  738.         Str_Grow(argstr,retval+1);
  739.         argstr->str_cur = retval;
  740.     }
  741.  
  742.  
  743.     s = argstr->str_ptr;
  744.     s[argstr->str_cur] = 17;    /* a little sanity check here */
  745.     }
  746.     else {
  747.     retval = (int)str_gnum(argstr);
  748. #ifdef MSDOS
  749.     s = (char*)(long)retval;        /* ouch */
  750. #else
  751.     s = (char*)retval;        /* ouch */
  752. #endif
  753.     }
  754.  
  755.  
  756. #ifndef lint
  757.     if (optype == O_IOCTL)
  758.     retval = ioctl(fileno(stio->ifp), func, s);
  759.     else
  760. #ifdef MSDOS
  761.     fatal("fcntl is not implemented");
  762. #else
  763. #ifdef HAS_FCNTL
  764.     retval = fcntl(fileno(stio->ifp), func, s);
  765. #else
  766.     fatal("fcntl is not implemented");
  767. #endif
  768. #endif
  769. #else /* lint */
  770.     retval = 0;
  771. #endif /* lint */
  772.  
  773.  
  774.     if (argstr->str_pok) {
  775.     if (s[argstr->str_cur] != 17)
  776.         fatal("Return value overflowed string");
  777.     s[argstr->str_cur] = 0;        /* put our null back */
  778.     }
  779.     return retval;
  780. }
  781.  
  782.  
  783. int
  784. do_stat(str,arg,gimme,arglast)
  785. STR *str;
  786. register ARG *arg;
  787. int gimme;
  788. int *arglast;
  789. {
  790.     register ARRAY *ary = stack;
  791.     register int sp = arglast[0] + 1;
  792.     int max = 13;
  793.  
  794.  
  795.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  796.     tmpstab = arg[1].arg_ptr.arg_stab;
  797.     if (tmpstab != defstab) {
  798.         laststype = O_STAT;
  799.         statstab = tmpstab;
  800.         str_set(statname,"");
  801.         if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  802.           fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
  803.         max = 0;
  804.         laststatval = -1;
  805.         }
  806.     }
  807.     else if (laststatval < 0)
  808.         max = 0;
  809.     }
  810.     else {
  811.     str_set(statname,str_get(ary->ary_array[sp]));
  812.     statstab = Nullstab;
  813. #ifdef HAS_LSTAT
  814.     laststype = arg->arg_type;
  815.     if (arg->arg_type == O_LSTAT)
  816.         laststatval = lstat(str_get(statname),&statcache);
  817.     else
  818. #endif
  819.         laststatval = stat(str_get(statname),&statcache);
  820.     if (laststatval < 0)
  821.         max = 0;
  822.     }
  823.  
  824.  
  825.     if (gimme != G_ARRAY) {
  826.     if (max)
  827.         str_sset(str,&str_yes);
  828.     else
  829.         str_sset(str,&str_undef);
  830.     STABSET(str);
  831.     ary->ary_array[sp] = str;
  832.     return sp;
  833.     }
  834.     sp--;
  835.     if (max) {
  836. #ifndef lint
  837.     (void)astore(ary,++sp,
  838.       str_2mortal(str_nmake((double)statcache.st_dev)));
  839.     (void)astore(ary,++sp,
  840.       str_2mortal(str_nmake((double)statcache.st_ino)));
  841.     (void)astore(ary,++sp,
  842.       str_2mortal(str_nmake((double)statcache.st_mode)));
  843.     (void)astore(ary,++sp,
  844.       str_2mortal(str_nmake((double)statcache.st_nlink)));
  845.     (void)astore(ary,++sp,
  846.       str_2mortal(str_nmake((double)statcache.st_uid)));
  847.     (void)astore(ary,++sp,
  848.       str_2mortal(str_nmake((double)statcache.st_gid)));
  849.     (void)astore(ary,++sp,
  850.       str_2mortal(str_nmake((double)statcache.st_rdev)));
  851.     (void)astore(ary,++sp,
  852.       str_2mortal(str_nmake((double)statcache.st_size)));
  853.     (void)astore(ary,++sp,
  854.       str_2mortal(str_nmake((double)statcache.st_atime)));
  855.     (void)astore(ary,++sp,
  856.       str_2mortal(str_nmake((double)statcache.st_mtime)));
  857.     (void)astore(ary,++sp,
  858.       str_2mortal(str_nmake((double)statcache.st_ctime)));
  859. #ifdef STATBLOCKS
  860.     (void)astore(ary,++sp,
  861.       str_2mortal(str_nmake((double)statcache.st_blksize)));
  862.     (void)astore(ary,++sp,
  863.       str_2mortal(str_nmake((double)statcache.st_blocks)));
  864. #else
  865.     (void)astore(ary,++sp,
  866.       str_2mortal(str_make("",0)));
  867.     (void)astore(ary,++sp,
  868.       str_2mortal(str_make("",0)));
  869. #endif
  870. #else /* lint */
  871.     (void)astore(ary,++sp,str_nmake(0.0));
  872. #endif /* lint */
  873.     }
  874.     return sp;
  875. }
  876.  
  877.  
  878. #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
  879.     /* code courtesy of William Kucharski */
  880. #define HAS_CHSIZE
  881.  
  882.  
  883. int chsize(fd, length)
  884. int fd;            /* file descriptor */
  885. off_t length;        /* length to set file to */
  886. {
  887.     extern long lseek();
  888.     struct flock fl;
  889.     struct stat filebuf;
  890.  
  891.  
  892.     if (fstat(fd, &filebuf) < 0)
  893.     return -1;
  894.  
  895.  
  896.     if (filebuf.st_size < length) {
  897.  
  898.  
  899.     /* extend file length */
  900.  
  901.  
  902.     if ((lseek(fd, (length - 1), 0)) < 0)
  903.         return -1;
  904.  
  905.  
  906.     /* write a "0" byte */
  907.  
  908.  
  909.     if ((write(fd, "", 1)) != 1)
  910.         return -1;
  911.     }
  912.     else {
  913.     /* truncate length */
  914.  
  915.  
  916.     fl.l_whence = 0;
  917.     fl.l_len = 0;
  918.     fl.l_start = length;
  919.     fl.l_type = F_WRLCK;    /* write lock on file space */
  920.  
  921.  
  922.     /*
  923.     * This relies on the UNDOCUMENTED F_FREESP argument to
  924.     * fcntl(2), which truncates the file so that it ends at the
  925.     * position indicated by fl.l_start.
  926.     *
  927.     * Will minor miracles never cease?
  928.     */
  929.  
  930.  
  931.     if (fcntl(fd, F_FREESP, &fl) < 0)
  932.         return -1;
  933.  
  934.  
  935.     }
  936.  
  937.  
  938.     return 0;
  939. }
  940. #endif /* F_FREESP */
  941.  
  942.  
  943. int                    /*SUPPRESS 590*/
  944. do_truncate(str,arg,gimme,arglast)
  945. STR *str;
  946. register ARG *arg;
  947. int gimme;
  948. int *arglast;
  949. {
  950.     register ARRAY *ary = stack;
  951.     register int sp = arglast[0] + 1;
  952.     off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
  953.     int result = 1;
  954.     STAB *tmpstab;
  955.  
  956.  
  957. #if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
  958. #ifdef HAS_TRUNCATE
  959.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  960.     tmpstab = arg[1].arg_ptr.arg_stab;
  961.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  962.       ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
  963.         result = 0;
  964.     }
  965.     else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
  966.     result = 0;
  967. #else
  968.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  969.     tmpstab = arg[1].arg_ptr.arg_stab;
  970.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  971.       chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
  972.         result = 0;
  973.     }
  974.     else {
  975.     int tmpfd;
  976.  
  977.  
  978.     if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
  979.         result = 0;
  980.     else {
  981.         if (chsize(tmpfd, len) < 0)
  982.         result = 0;
  983.         close(tmpfd);
  984.     }
  985.     }
  986. #endif
  987.  
  988.  
  989.     if (result)
  990.     str_sset(str,&str_yes);
  991.     else
  992.     str_sset(str,&str_undef);
  993.     STABSET(str);
  994.     ary->ary_array[sp] = str;
  995.     return sp;
  996. #else
  997.     fatal("truncate not implemented");
  998. #endif
  999. }
  1000.  
  1001.  
  1002. int
  1003. looks_like_number(str)
  1004. STR *str;
  1005. {
  1006.     register char *s;
  1007.     register char *send;
  1008.  
  1009.  
  1010.     if (!str->str_pok)
  1011.     return TRUE;
  1012.     s = str->str_ptr;
  1013.     send = s + str->str_cur;
  1014.     while (isSPACE(*s))
  1015.     s++;
  1016.     if (s >= send)
  1017.     return FALSE;
  1018.     if (*s == '+' || *s == '-')
  1019.     s++;
  1020.     while (isDIGIT(*s))
  1021.     s++;
  1022.     if (s == send)
  1023.     return TRUE;
  1024.     if (*s == '.')
  1025.     s++;
  1026.     else if (s == str->str_ptr)
  1027.     return FALSE;
  1028.     while (isDIGIT(*s))
  1029.     s++;
  1030.     if (s == send)
  1031.     return TRUE;
  1032.     if (*s == 'e' || *s == 'E') {
  1033.     s++;
  1034.     if (*s == '+' || *s == '-')
  1035.         s++;
  1036.     while (isDIGIT(*s))
  1037.         s++;
  1038.     }
  1039.     while (isSPACE(*s))
  1040.     s++;
  1041.     if (s >= send)
  1042.     return TRUE;
  1043.     return FALSE;
  1044. }
  1045.  
  1046.  
  1047. bool
  1048. do_print(str,fp)
  1049. register STR *str;
  1050. FILE *fp;
  1051. {
  1052.     register char *tmps;
  1053.  
  1054.  
  1055.     if (!fp) {
  1056.     if (dowarn)
  1057.         warn("print to unopened file");
  1058.     errno = EBADF;
  1059.     return FALSE;
  1060.     }
  1061.     if (!str)
  1062.     return TRUE;
  1063.     if (ofmt &&
  1064.       ((str->str_nok && str->str_u.str_nval != 0.0)
  1065.        || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
  1066.     fprintf(fp, ofmt, str->str_u.str_nval);
  1067.     return !ferror(fp);
  1068.     }
  1069.     else {
  1070.     tmps = str_get(str);
  1071.     if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
  1072.       && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
  1073.         STR *tmpstr = str_mortal(&str_undef);
  1074.         stab_fullname(tmpstr,((STAB*)str));/* a stab value, be nice */
  1075.         str = tmpstr;
  1076.         tmps = str->str_ptr;
  1077.         putc('*',fp);
  1078.     }
  1079.     if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
  1080.         return FALSE;
  1081.     }
  1082.     return TRUE;
  1083. }
  1084.  
  1085.  
  1086. bool
  1087. do_aprint(arg,fp,arglast)
  1088. register ARG *arg;
  1089. register FILE *fp;
  1090. int *arglast;
  1091. {
  1092.     register STR **st = stack->ary_array;
  1093.     register int sp = arglast[1];
  1094.     register int retval;
  1095.     register int items = arglast[2] - sp;
  1096.  
  1097.  
  1098.     if (!fp) {
  1099.     if (dowarn)
  1100.         warn("print to unopened file");
  1101.     errno = EBADF;
  1102.     return FALSE;
  1103.     }
  1104.     st += ++sp;
  1105.     if (arg->arg_type == O_PRTF) {
  1106.     do_sprintf(arg->arg_ptr.arg_str,items,st);
  1107.     retval = do_print(arg->arg_ptr.arg_str,fp);
  1108.     }
  1109.     else {
  1110.     retval = (items <= 0);
  1111.     for (; items > 0; items--,st++) {
  1112.         if (retval && ofslen) {
  1113.         if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
  1114.             retval = FALSE;
  1115.             break;
  1116.         }
  1117.         }
  1118.         if (!(retval = do_print(*st, fp)))
  1119.         break;
  1120.     }
  1121.     if (retval && orslen)
  1122.         if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
  1123.         retval = FALSE;
  1124.     }
  1125.     return retval;
  1126. }
  1127.  
  1128.  
  1129. int
  1130. mystat(arg,str)
  1131. ARG *arg;
  1132. STR *str;
  1133. {
  1134.     STIO *stio;
  1135.  
  1136.  
  1137.     if (arg[1].arg_type & A_DONT) {
  1138.     stio = stab_io(arg[1].arg_ptr.arg_stab);
  1139.     if (stio && stio->ifp) {
  1140.         statstab = arg[1].arg_ptr.arg_stab;
  1141.         str_set(statname,"");
  1142.         laststype = O_STAT;
  1143.         return (laststatval = fstat(fileno(stio->ifp), &statcache));
  1144.     }
  1145.     else {
  1146.         if (arg[1].arg_ptr.arg_stab == defstab)
  1147.         return laststatval;
  1148.         if (dowarn)
  1149.         warn("Stat on unopened file <%s>",
  1150.           stab_name(arg[1].arg_ptr.arg_stab));
  1151.         statstab = Nullstab;
  1152.         str_set(statname,"");
  1153.         return (laststatval = -1);
  1154.     }
  1155.     }
  1156.     else {
  1157.     statstab = Nullstab;
  1158.     str_set(statname,str_get(str));
  1159.     laststype = O_STAT;
  1160.     return (laststatval = stat(str_get(str),&statcache));
  1161.     }
  1162. }
  1163.  
  1164.  
  1165. int
  1166. mylstat(arg,str)
  1167. ARG *arg;
  1168. STR *str;
  1169. {
  1170.     if (arg[1].arg_type & A_DONT) {
  1171.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1172.         if (laststype != O_LSTAT)
  1173.         fatal("The stat preceding -l _ wasn't an lstat");
  1174.         return laststatval;
  1175.     }
  1176.     fatal("You can't use -l on a filehandle");
  1177.     }
  1178.  
  1179.  
  1180.     laststype = O_LSTAT;
  1181.     statstab = Nullstab;
  1182.     str_set(statname,str_get(str));
  1183. #ifdef HAS_LSTAT
  1184.     return (laststatval = lstat(str_get(str),&statcache));
  1185. #else
  1186.     return (laststatval = stat(str_get(str),&statcache));
  1187. #endif
  1188. }
  1189.  
  1190.  
  1191. STR *
  1192. do_fttext(arg,str)
  1193. register ARG *arg;
  1194. STR *str;
  1195. {
  1196.     int i;
  1197.     int len;
  1198.     int odd = 0;
  1199.     STDCHAR tbuf[512];
  1200.     register STDCHAR *s;
  1201.     register STIO *stio;
  1202.  
  1203.  
  1204.     if (arg[1].arg_type & A_DONT) {
  1205.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1206.         if (statstab)
  1207.         stio = stab_io(statstab);
  1208.         else {
  1209.         str = statname;
  1210.         goto really_filename;
  1211.         }
  1212.     }
  1213.     else {
  1214.         statstab = arg[1].arg_ptr.arg_stab;
  1215.         str_set(statname,"");
  1216.         stio = stab_io(statstab);
  1217.     }
  1218.     if (stio && stio->ifp) {
  1219. #ifdef STDSTDIO
  1220.         fstat(fileno(stio->ifp),&statcache);
  1221.         if (S_ISDIR(statcache.st_mode))    /* handle NFS glitch */
  1222.         return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
  1223.         if (stio->ifp->_cnt <= 0) {
  1224.         i = getc(stio->ifp);
  1225.         if (i != EOF)
  1226.             (void)ungetc(i,stio->ifp);
  1227.         }
  1228.         if (stio->ifp->_cnt <= 0)    /* null file is anything */
  1229.         return &str_yes;
  1230.         len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
  1231.         s = stio->ifp->_base;
  1232. #else
  1233.         fatal("-T and -B not implemented on filehandles");
  1234. #endif
  1235.     }
  1236.     else {
  1237.         if (dowarn)
  1238.         warn("Test on unopened file <%s>",
  1239.           stab_name(arg[1].arg_ptr.arg_stab));
  1240.         errno = EBADF;
  1241.         return &str_undef;
  1242.     }
  1243.     }
  1244.     else {
  1245.     statstab = Nullstab;
  1246.     str_set(statname,str_get(str));
  1247.       really_filename:
  1248.     i = open(str_get(str),0);
  1249.     if (i < 0)
  1250.         return &str_undef;
  1251.     fstat(i,&statcache);
  1252.     len = read(i,tbuf,512);
  1253.     (void)close(i);
  1254.     if (len <= 0) {
  1255.         if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
  1256.         return &str_no;        /* special case NFS directories */
  1257.         return &str_yes;        /* null file is anything */
  1258.     }
  1259.     s = tbuf;
  1260.     }
  1261.  
  1262.  
  1263.     /* now scan s to look for textiness */
  1264.  
  1265.  
  1266.     for (i = 0; i < len; i++,s++) {
  1267.     if (!*s) {            /* null never allowed in text */
  1268.         odd += len;
  1269.         break;
  1270.     }
  1271.     else if (*s & 128)
  1272.         odd++;
  1273.     else if (*s < 32 &&
  1274.       *s != '\n' && *s != '\r' && *s != '\b' &&
  1275.       *s != '\t' && *s != '\f' && *s != 27)
  1276.         odd++;
  1277.     }
  1278.  
  1279.  
  1280.     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
  1281.     return &str_no;
  1282.     else
  1283.     return &str_yes;
  1284. }
  1285.  
  1286.  
  1287. bool
  1288. do_aexec(really,arglast)
  1289. STR *really;
  1290. int *arglast;
  1291. {
  1292.     register STR **st = stack->ary_array;
  1293.     register int sp = arglast[1];
  1294.     register int items = arglast[2] - sp;
  1295.     register char **a;
  1296.     char **argv;
  1297.     char *tmps;
  1298.  
  1299.  
  1300.     if (items) {
  1301.     New(401,argv, items+1, char*);
  1302.     a = argv;
  1303.     for (st += ++sp; items > 0; items--,st++) {
  1304.         if (*st)
  1305.         *a++ = str_get(*st);
  1306.         else
  1307.         *a++ = "";
  1308.     }
  1309.     *a = Nullch;
  1310. #ifdef TAINT
  1311.     if (*argv[0] != '/')    /* will execvp use PATH? */
  1312.         taintenv();        /* testing IFS here is overkill, probably */
  1313. #endif
  1314.     if (really && *(tmps = str_get(really)))
  1315.         execvp(tmps,argv);
  1316.     else
  1317.         execvp(argv[0],argv);
  1318.     Safefree(argv);
  1319.     }
  1320.     return FALSE;
  1321. }
  1322.  
  1323.  
  1324. static char **Argv = Null(char **);
  1325. static char *Cmd = Nullch;
  1326.  
  1327.  
  1328. void
  1329. do_execfree()
  1330. {
  1331.     if (Argv) {
  1332.     Safefree(Argv);
  1333.     Argv = Null(char **);
  1334.     }
  1335.     if (Cmd) {
  1336.     Safefree(Cmd);
  1337.     Cmd = Nullch;
  1338.     }
  1339. }
  1340.  
  1341.  
  1342. bool
  1343. do_exec(cmd)
  1344. char *cmd;
  1345. {
  1346.     register char **a;
  1347.     register char *s;
  1348.     char flags[10];
  1349.  
  1350.  
  1351.     /* save an extra exec if possible */
  1352.  
  1353.  
  1354. #ifdef CSH
  1355.     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
  1356.     strcpy(flags,"-c");
  1357.     s = cmd+cshlen+3;
  1358.     if (*s == 'f') {
  1359.         s++;
  1360.         strcat(flags,"f");
  1361.     }
  1362.     if (*s == ' ')
  1363.         s++;
  1364.     if (*s++ == '\'') {
  1365.         char *ncmd = s;
  1366.  
  1367.  
  1368.         while (*s)
  1369.         s++;
  1370.         if (s[-1] == '\n')
  1371.         *--s = '\0';
  1372.         if (s[-1] == '\'') {
  1373.         *--s = '\0';
  1374.         execl(cshname,"csh", flags,ncmd,(char*)0);
  1375.         *s = '\'';
  1376.         return FALSE;
  1377.         }
  1378.     }
  1379.     }
  1380. #endif /* CSH */
  1381.  
  1382.  
  1383.     /* see if there are shell metacharacters in it */
  1384.  
  1385.  
  1386.     /*SUPPRESS 530*/
  1387.     for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
  1388.     if (*s == '=')
  1389.     goto doshell;
  1390.     for (s = cmd; *s; s++) {
  1391.     if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
  1392.         if (*s == '\n' && !s[1]) {
  1393.         *s = '\0';
  1394.         break;
  1395.         }
  1396.       doshell:
  1397.         execl("/bin/sh","sh","-c",cmd,(char*)0);
  1398.         return FALSE;
  1399.     }
  1400.     }
  1401.     New(402,Argv, (s - cmd) / 2 + 2, char*);
  1402.     Cmd = nsavestr(cmd, s-cmd);
  1403.     a = Argv;
  1404.     for (s = Cmd; *s;) {
  1405.     while (*s && isSPACE(*s)) s++;
  1406.     if (*s)
  1407.         *(a++) = s;
  1408.     while (*s && !isSPACE(*s)) s++;
  1409.     if (*s)
  1410.         *s++ = '\0';
  1411.     }
  1412.     *a = Nullch;
  1413.     if (Argv[0]) {
  1414.     execvp(Argv[0],Argv);
  1415.     if (errno == ENOEXEC) {        /* for system V NIH syndrome */
  1416.         do_execfree();
  1417.         goto doshell;
  1418.     }
  1419.     }
  1420.     do_execfree();
  1421.     return FALSE;
  1422. }
  1423.  
  1424.  
  1425. #ifdef HAS_SOCKET
  1426. int
  1427. do_socket(stab, arglast)
  1428. STAB *stab;
  1429. int *arglast;
  1430. {
  1431.     register STR **st = stack->ary_array;
  1432.     register int sp = arglast[1];
  1433.     register STIO *stio;
  1434.     int domain, type, protocol, fd;
  1435.  
  1436.  
  1437.     if (!stab) {
  1438.     errno = EBADF;
  1439.     return FALSE;
  1440.     }
  1441.  
  1442.  
  1443.     stio = stab_io(stab);
  1444.     if (!stio)
  1445.     stio = stab_io(stab) = stio_new();
  1446.     else if (stio->ifp)
  1447.     do_close(stab,FALSE);
  1448.  
  1449.  
  1450.     domain = (int)str_gnum(st[++sp]);
  1451.     type = (int)str_gnum(st[++sp]);
  1452.     protocol = (int)str_gnum(st[++sp]);
  1453. #ifdef TAINT
  1454.     taintproper("Insecure dependency in socket");
  1455. #endif
  1456.     fd = socket(domain,type,protocol);
  1457.     if (fd < 0)
  1458.     return FALSE;
  1459.     stio->ifp = fdopen(fd, "r");    /* stdio gets confused about sockets */
  1460.     stio->ofp = fdopen(fd, "w");
  1461.     stio->type = 's';
  1462.     if (!stio->ifp || !stio->ofp) {
  1463.     if (stio->ifp) fclose(stio->ifp);
  1464.     if (stio->ofp) fclose(stio->ofp);
  1465.     if (!stio->ifp && !stio->ofp) close(fd);
  1466.     return FALSE;
  1467.     }
  1468.  
  1469.  
  1470.     return TRUE;
  1471. }
  1472.  
  1473.  
  1474. int
  1475. do_bind(stab, arglast)
  1476. STAB *stab;
  1477. int *arglast;
  1478. {
  1479.     register STR **st = stack->ary_array;
  1480.     register int sp = arglast[1];
  1481.     register STIO *stio;
  1482.     char *addr;
  1483.  
  1484.  
  1485.     if (!stab)
  1486.     goto nuts;
  1487.  
  1488.  
  1489.     stio = stab_io(stab);
  1490.     if (!stio || !stio->ifp)
  1491.     goto nuts;
  1492.  
  1493.  
  1494.     addr = str_get(st[++sp]);
  1495. #ifdef TAINT
  1496.     taintproper("Insecure dependency in bind");
  1497. #endif
  1498.     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1499.  
  1500.  
  1501. nuts:
  1502.     if (dowarn)
  1503.     warn("bind() on closed fd");
  1504.     errno = EBADF;
  1505.     return FALSE;
  1506.  
  1507.  
  1508. }
  1509.  
  1510.  
  1511. int
  1512. do_connect(stab, arglast)
  1513. STAB *stab;
  1514. int *arglast;
  1515. {
  1516.     register STR **st = stack->ary_array;
  1517.     register int sp = arglast[1];
  1518.     register STIO *stio;
  1519.     char *addr;
  1520.  
  1521.  
  1522.     if (!stab)
  1523.     goto nuts;
  1524.  
  1525.  
  1526.     stio = stab_io(stab);
  1527.     if (!stio || !stio->ifp)
  1528.     goto nuts;
  1529.  
  1530.  
  1531.     addr = str_get(st[++sp]);
  1532. #ifdef TAINT
  1533.     taintproper("Insecure dependency in connect");
  1534. #endif
  1535.     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1536.  
  1537.  
  1538. nuts:
  1539.     if (dowarn)
  1540.     warn("connect() on closed fd");
  1541.     errno = EBADF;
  1542.     return FALSE;
  1543.  
  1544.  
  1545. }
  1546.  
  1547.  
  1548. int
  1549. do_listen(stab, arglast)
  1550. STAB *stab;
  1551. int *arglast;
  1552. {
  1553.     register STR **st = stack->ary_array;
  1554.     register int sp = arglast[1];
  1555.     register STIO *stio;
  1556.     int backlog;
  1557.  
  1558.  
  1559.     if (!stab)
  1560.     goto nuts;
  1561.  
  1562.  
  1563.     stio = stab_io(stab);
  1564.     if (!stio || !stio->ifp)
  1565.     goto nuts;
  1566.  
  1567.  
  1568.     backlog = (int)str_gnum(st[++sp]);
  1569.     return listen(fileno(stio->ifp), backlog) >= 0;
  1570.  
  1571.  
  1572. nuts:
  1573.     if (dowarn)
  1574.     warn("listen() on closed fd");
  1575.     errno = EBADF;
  1576.     return FALSE;
  1577. }
  1578.  
  1579.  
  1580. void
  1581. do_accept(str, nstab, gstab)
  1582. STR *str;
  1583. STAB *nstab;
  1584. STAB *gstab;
  1585. {
  1586.     register STIO *nstio;
  1587.     register STIO *gstio;
  1588.     int len = sizeof buf;
  1589.     int fd;
  1590.  
  1591.  
  1592.     if (!nstab)
  1593.     goto badexit;
  1594.     if (!gstab)
  1595.     goto nuts;
  1596.  
  1597.  
  1598.     gstio = stab_io(gstab);
  1599.     nstio = stab_io(nstab);
  1600.  
  1601.  
  1602.     if (!gstio || !gstio->ifp)
  1603.     goto nuts;
  1604.     if (!nstio)
  1605.     nstio = stab_io(nstab) = stio_new();
  1606.     else if (nstio->ifp)
  1607.     do_close(nstab,FALSE);
  1608.  
  1609.  
  1610.     fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
  1611.     if (fd < 0)
  1612.     goto badexit;
  1613.     nstio->ifp = fdopen(fd, "r");
  1614.     nstio->ofp = fdopen(fd, "w");
  1615.     nstio->type = 's';
  1616.     if (!nstio->ifp || !nstio->ofp) {
  1617.     if (nstio->ifp) fclose(nstio->ifp);
  1618.     if (nstio->ofp) fclose(nstio->ofp);
  1619.     if (!nstio->ifp && !nstio->ofp) close(fd);
  1620.     goto badexit;
  1621.     }
  1622.  
  1623.  
  1624.     str_nset(str, buf, len);
  1625.     return;
  1626.  
  1627.  
  1628. nuts:
  1629.     if (dowarn)
  1630.     warn("accept() on closed fd");
  1631.     errno = EBADF;
  1632. badexit:
  1633.     str_sset(str,&str_undef);
  1634.     return;
  1635. }
  1636.  
  1637.  
  1638. int
  1639. do_shutdown(stab, arglast)
  1640. STAB *stab;
  1641. int *arglast;
  1642. {
  1643.     register STR **st = stack->ary_array;
  1644.     register int sp = arglast[1];
  1645.     register STIO *stio;
  1646.     int how;
  1647.  
  1648.  
  1649.     if (!stab)
  1650.     goto nuts;
  1651.  
  1652.  
  1653.     stio = stab_io(stab);
  1654.     if (!stio || !stio->ifp)
  1655.     goto nuts;
  1656.  
  1657.  
  1658.     how = (int)str_gnum(st[++sp]);
  1659.     return shutdown(fileno(stio->ifp), how) >= 0;
  1660.  
  1661.  
  1662. nuts:
  1663.     if (dowarn)
  1664.     warn("shutdown() on closed fd");
  1665.     errno = EBADF;
  1666.     return FALSE;
  1667.  
  1668.  
  1669. }
  1670.  
  1671.  
  1672. int
  1673. do_sopt(optype, stab, arglast)
  1674. int optype;
  1675. STAB *stab;
  1676. int *arglast;
  1677. {
  1678.     register STR **st = stack->ary_array;
  1679.     register int sp = arglast[1];
  1680.     register STIO *stio;
  1681.     int fd;
  1682.     int lvl;
  1683.     int optname;
  1684.  
  1685.  
  1686.     if (!stab)
  1687.     goto nuts;
  1688.  
  1689.  
  1690.     stio = stab_io(stab);
  1691.     if (!stio || !stio->ifp)
  1692.     goto nuts;
  1693.  
  1694.  
  1695.     fd = fileno(stio->ifp);
  1696.     lvl = (int)str_gnum(st[sp+1]);
  1697.     optname = (int)str_gnum(st[sp+2]);
  1698.     switch (optype) {
  1699.     case O_GSOCKOPT:
  1700.     st[sp] = str_2mortal(Str_new(22,257));
  1701.     st[sp]->str_cur = 256;
  1702.     st[sp]->str_pok = 1;
  1703.     if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
  1704.         goto nuts;
  1705.     break;
  1706.     case O_SSOCKOPT:
  1707.     st[sp] = st[sp+3];
  1708.     if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
  1709.         goto nuts;
  1710.     st[sp] = &str_yes;
  1711.     break;
  1712.     }
  1713.  
  1714.     return sp;
  1715.  
  1716.  
  1717. nuts:
  1718.     if (dowarn)
  1719.     warn("[gs]etsockopt() on closed fd");
  1720.     st[sp] = &str_undef;
  1721.     errno = EBADF;
  1722.     return sp;
  1723.  
  1724.  
  1725. }
  1726.  
  1727.  
  1728. int
  1729. do_getsockname(optype, stab, arglast)
  1730. int optype;
  1731. STAB *stab;
  1732. int *arglast;
  1733. {
  1734.     register STR **st = stack->ary_array;
  1735.     register int sp = arglast[1];
  1736.     register STIO *stio;
  1737.     int fd;
  1738.  
  1739.  
  1740.     if (!stab)
  1741.     goto nuts;
  1742.  
  1743.  
  1744.     stio = stab_io(stab);
  1745.     if (!stio || !stio->ifp)
  1746.     goto nuts;
  1747.  
  1748.  
  1749.     st[sp] = str_2mortal(Str_new(22,257));
  1750.     st[sp]->str_cur = 256;
  1751.     st[sp]->str_pok = 1;
  1752.     fd = fileno(stio->ifp);
  1753.     switch (optype) {
  1754.     case O_GETSOCKNAME:
  1755.     if (getsockname(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
  1756.         goto nuts2;
  1757.     break;
  1758.     case O_GETPEERNAME:
  1759.     if (getpeername(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
  1760.         goto nuts2;
  1761.     break;
  1762.     }
  1763.  
  1764.     return sp;
  1765.  
  1766.  
  1767. nuts:
  1768.     if (dowarn)
  1769.     warn("get{sock,peer}name() on closed fd");
  1770.     errno = EBADF;
  1771. nuts2:
  1772.     st[sp] = &str_undef;
  1773.     return sp;
  1774.  
  1775.  
  1776. }
  1777.  
  1778.  
  1779. int
  1780. do_ghent(which,gimme,arglast)
  1781. int which;
  1782. int gimme;
  1783. int *arglast;
  1784. {
  1785.     register ARRAY *ary = stack;
  1786.     register int sp = arglast[0];
  1787.     register char **elem;
  1788.     register STR *str;
  1789.     struct hostent *gethostbyname();
  1790.     struct hostent *gethostbyaddr();
  1791. #ifdef HAS_GETHOSTENT
  1792.     struct hostent *gethostent();
  1793. #endif
  1794.     struct hostent *hent;
  1795.     unsigned long len;
  1796.  
  1797.  
  1798.     if (gimme != G_ARRAY) {
  1799.     astore(ary, ++sp, str_mortal(&str_undef));
  1800.     return sp;
  1801.     }
  1802.  
  1803.  
  1804.     if (which == O_GHBYNAME) {
  1805.     char *name = str_get(ary->ary_array[sp+1]);
  1806.  
  1807.  
  1808.     hent = gethostbyname(name);
  1809.     }
  1810.     else if (which == O_GHBYADDR) {
  1811.     STR *addrstr = ary->ary_array[sp+1];
  1812.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1813.     char *addr = str_get(addrstr);
  1814.  
  1815.  
  1816.     hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
  1817.     }
  1818.     else
  1819. #ifdef HAS_GETHOSTENT
  1820.     hent = gethostent();
  1821. #else
  1822.     fatal("gethostent not implemented");
  1823. #endif
  1824.     if (hent) {
  1825. #ifndef lint
  1826.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1827.     str_set(str, hent->h_name);
  1828.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1829.     for (elem = hent->h_aliases; *elem; elem++) {
  1830.         str_cat(str, *elem);
  1831.         if (elem[1])
  1832.         str_ncat(str," ",1);
  1833.     }
  1834.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1835.     str_numset(str, (double)hent->h_addrtype);
  1836.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1837.     len = hent->h_length;
  1838.     str_numset(str, (double)len);
  1839. #ifdef h_addr
  1840.     for (elem = hent->h_addr_list; *elem; elem++) {
  1841.         (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1842.         str_nset(str, *elem, len);
  1843.     }
  1844. #else
  1845.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1846.     str_nset(str, hent->h_addr, len);
  1847. #endif /* h_addr */
  1848. #else /* lint */
  1849.     elem = Nullch;
  1850.     elem = elem;
  1851.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1852. #endif /* lint */
  1853.     }
  1854.  
  1855.  
  1856.     return sp;
  1857. }
  1858.  
  1859.  
  1860. int
  1861. do_gnent(which,gimme,arglast)
  1862. int which;
  1863. int gimme;
  1864. int *arglast;
  1865. {
  1866.     register ARRAY *ary = stack;
  1867.     register int sp = arglast[0];
  1868.     register char **elem;
  1869.     register STR *str;
  1870.     struct netent *getnetbyname();
  1871.     struct netent *getnetbyaddr();
  1872.     struct netent *getnetent();
  1873.     struct netent *nent;
  1874.  
  1875.  
  1876.     if (gimme != G_ARRAY) {
  1877.     astore(ary, ++sp, str_mortal(&str_undef));
  1878.     return sp;
  1879.     }
  1880.  
  1881.  
  1882.     if (which == O_GNBYNAME) {
  1883.     char *name = str_get(ary->ary_array[sp+1]);
  1884.  
  1885.  
  1886.     nent = getnetbyname(name);
  1887.     }
  1888.     else if (which == O_GNBYADDR) {
  1889.     unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
  1890.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1891.  
  1892.  
  1893.     nent = getnetbyaddr((long)addr,addrtype);
  1894.     }
  1895.     else
  1896.     nent = getnetent();
  1897.  
  1898.  
  1899.     if (nent) {
  1900. #ifndef lint
  1901.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1902.     str_set(str, nent->n_name);
  1903.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1904.     for (elem = nent->n_aliases; *elem; elem++) {
  1905.         str_cat(str, *elem);
  1906.         if (elem[1])
  1907.         str_ncat(str," ",1);
  1908.     }
  1909.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1910.     str_numset(str, (double)nent->n_addrtype);
  1911.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1912.     str_numset(str, (double)nent->n_net);
  1913. #else /* lint */
  1914.     elem = Nullch;
  1915.     elem = elem;
  1916.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1917. #endif /* lint */
  1918.     }
  1919.  
  1920.  
  1921.     return sp;
  1922. }
  1923.  
  1924.  
  1925. int
  1926. do_gpent(which,gimme,arglast)
  1927. int which;
  1928. int gimme;
  1929. int *arglast;
  1930. {
  1931.     register ARRAY *ary = stack;
  1932.     register int sp = arglast[0];
  1933.     register char **elem;
  1934.     register STR *str;
  1935.     struct protoent *getprotobyname();
  1936.     struct protoent *getprotobynumber();
  1937.     struct protoent *getprotoent();
  1938.     struct protoent *pent;
  1939.  
  1940.  
  1941.     if (gimme != G_ARRAY) {
  1942.     astore(ary, ++sp, str_mortal(&str_undef));
  1943.     return sp;
  1944.     }
  1945.  
  1946.  
  1947.     if (which == O_GPBYNAME) {
  1948.     char *name = str_get(ary->ary_array[sp+1]);
  1949.  
  1950.  
  1951.     pent = getprotobyname(name);
  1952.     }
  1953.     else if (which == O_GPBYNUMBER) {
  1954.     int proto = (int)str_gnum(ary->ary_array[sp+1]);
  1955.  
  1956.  
  1957.     pent = getprotobynumber(proto);
  1958.     }
  1959.     else
  1960.     pent = getprotoent();
  1961.  
  1962.  
  1963.     if (pent) {
  1964. #ifndef lint
  1965.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1966.     str_set(str, pent->p_name);
  1967.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1968.     for (elem = pent->p_aliases; *elem; elem++) {
  1969.         str_cat(str, *elem);
  1970.         if (elem[1])
  1971.         str_ncat(str," ",1);
  1972.     }
  1973.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1974.     str_numset(str, (double)pent->p_proto);
  1975. #else /* lint */
  1976.     elem = Nullch;
  1977.     elem = elem;
  1978.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1979. #endif /* lint */
  1980.     }
  1981.  
  1982.  
  1983.     return sp;
  1984. }
  1985.  
  1986.  
  1987. int
  1988. do_gsent(which,gimme,arglast)
  1989. int which;
  1990. int gimme;
  1991. int *arglast;
  1992. {
  1993.     register ARRAY *ary = stack;
  1994.     register int sp = arglast[0];
  1995.     register char **elem;
  1996.     register STR *str;
  1997.     struct servent *getservbyname();
  1998.     struct servent *getservbynumber();
  1999.     struct servent *getservent();
  2000.     struct servent *sent;
  2001.  
  2002.  
  2003.     if (gimme != G_ARRAY) {
  2004.     astore(ary, ++sp, str_mortal(&str_undef));
  2005.     return sp;
  2006.     }
  2007.  
  2008.  
  2009.     if (which == O_GSBYNAME) {
  2010.     char *name = str_get(ary->ary_array[sp+1]);
  2011.     char *proto = str_get(ary->ary_array[sp+2]);
  2012.  
  2013.  
  2014.     if (proto && !*proto)
  2015.         proto = Nullch;
  2016.  
  2017.  
  2018.     sent = getservbyname(name,proto);
  2019.     }
  2020.     else if (which == O_GSBYPORT) {
  2021.     int port = (int)str_gnum(ary->ary_array[sp+1]);
  2022.     char *proto = str_get(ary->ary_array[sp+2]);
  2023.  
  2024.  
  2025.     sent = getservbyport(port,proto);
  2026.     }
  2027.     else
  2028.     sent = getservent();
  2029.     if (sent) {
  2030. #ifndef lint
  2031.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2032.     str_set(str, sent->s_name);
  2033.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2034.     for (elem = sent->s_aliases; *elem; elem++) {
  2035.         str_cat(str, *elem);
  2036.         if (elem[1])
  2037.         str_ncat(str," ",1);
  2038.     }
  2039.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2040. #ifdef HAS_NTOHS
  2041.     str_numset(str, (double)ntohs(sent->s_port));
  2042. #else
  2043.     str_numset(str, (double)(sent->s_port));
  2044. #endif
  2045.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2046.     str_set(str, sent->s_proto);
  2047. #else /* lint */
  2048.     elem = Nullch;
  2049.     elem = elem;
  2050.     (void)astore(ary, ++sp, str_mortal(&str_no));
  2051. #endif /* lint */
  2052.     }
  2053.  
  2054.  
  2055.     return sp;
  2056. }
  2057.  
  2058.  
  2059. #endif /* HAS_SOCKET */
  2060.  
  2061.  
  2062. #ifdef HAS_SELECT
  2063. int
  2064. do_select(gimme,arglast)
  2065. int gimme;
  2066. int *arglast;
  2067. {
  2068.     register STR **st = stack->ary_array;
  2069.     register int sp = arglast[0];
  2070.     register int i;
  2071.     register int j;
  2072.     register char *s;
  2073.     register STR *str;
  2074.     double value;
  2075.     int maxlen = 0;
  2076.     int nfound;
  2077.     struct timeval timebuf;
  2078.     struct timeval *tbuf = &timebuf;
  2079.     int growsize;
  2080. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2081.     int masksize;
  2082.     int offset;
  2083.     char *fd_sets[4];
  2084.     int k;
  2085.  
  2086.  
  2087. #if BYTEORDER & 0xf0000
  2088. #define ORDERBYTE (0x88888888 - BYTEORDER)
  2089. #else
  2090. #define ORDERBYTE (0x4444 - BYTEORDER)
  2091. #endif
  2092.  
  2093.  
  2094. #endif
  2095.  
  2096.  
  2097.     for (i = 1; i <= 3; i++) {
  2098.     j = st[sp+i]->str_cur;
  2099.     if (maxlen < j)
  2100.         maxlen = j;
  2101.     }
  2102.  
  2103.  
  2104. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2105.     growsize = maxlen;        /* little endians can use vecs directly */
  2106. #else
  2107. #ifdef NFDBITS
  2108.  
  2109.  
  2110. #ifndef NBBY
  2111. #define NBBY 8
  2112. #endif
  2113.  
  2114.  
  2115.     masksize = NFDBITS / NBBY;
  2116. #else
  2117.     masksize = sizeof(long);    /* documented int, everyone seems to use long */
  2118. #endif
  2119.     growsize = maxlen + (masksize - (maxlen % masksize));
  2120.     Zero(&fd_sets[0], 4, char*);
  2121. #endif
  2122.  
  2123.  
  2124.     for (i = 1; i <= 3; i++) {
  2125.     str = st[sp+i];
  2126.     j = str->str_len;
  2127.     if (j < growsize) {
  2128.         if (str->str_pok) {
  2129.         Str_Grow(str,growsize);
  2130.         s = str_get(str) + j;
  2131.         while (++j <= growsize) {
  2132.             *s++ = '\0';
  2133.         }
  2134.         }
  2135.         else if (str->str_ptr) {
  2136.         Safefree(str->str_ptr);
  2137.         str->str_ptr = Nullch;
  2138.         }
  2139.     }
  2140. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2141.     s = str->str_ptr;
  2142.     if (s) {
  2143.         New(403, fd_sets[i], growsize, char);
  2144.         for (offset = 0; offset < growsize; offset += masksize) {
  2145.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2146.             fd_sets[i][j+offset] = s[(k % masksize) + offset];
  2147.         }
  2148.     }
  2149. #endif
  2150.     }
  2151.     str = st[sp+4];
  2152.     if (str->str_nok || str->str_pok) {
  2153.     value = str_gnum(str);
  2154.     if (value < 0.0)
  2155.         value = 0.0;
  2156.     timebuf.tv_sec = (long)value;
  2157.     value -= (double)timebuf.tv_sec;
  2158.     timebuf.tv_usec = (long)(value * 1000000.0);
  2159.     }
  2160.     else
  2161.     tbuf = Null(struct timeval*);
  2162.  
  2163.  
  2164. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2165.     nfound = select(
  2166.     maxlen * 8,
  2167.     st[sp+1]->str_ptr,
  2168.     st[sp+2]->str_ptr,
  2169.     st[sp+3]->str_ptr,
  2170.     tbuf);
  2171. #else
  2172.     nfound = select(
  2173.     maxlen * 8,
  2174.     fd_sets[1],
  2175.     fd_sets[2],
  2176.     fd_sets[3],
  2177.     tbuf);
  2178.     for (i = 1; i <= 3; i++) {
  2179.     if (fd_sets[i]) {
  2180.         str = st[sp+i];
  2181.         s = str->str_ptr;
  2182.         for (offset = 0; offset < growsize; offset += masksize) {
  2183.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2184.             s[(k % masksize) + offset] = fd_sets[i][j+offset];
  2185.         }
  2186.     }
  2187.     }
  2188. #endif
  2189.  
  2190.  
  2191.     st[++sp] = str_mortal(&str_no);
  2192.     str_numset(st[sp], (double)nfound);
  2193.     if (gimme == G_ARRAY && tbuf) {
  2194.     value = (double)(timebuf.tv_sec) +
  2195.         (double)(timebuf.tv_usec) / 1000000.0;
  2196.     st[++sp] = str_mortal(&str_no);
  2197.     str_numset(st[sp], value);
  2198.     }
  2199.     return sp;
  2200. }
  2201. #endif /* SELECT */
  2202.  
  2203.  
  2204. #ifdef HAS_SOCKET
  2205. int
  2206. do_spair(stab1, stab2, arglast)
  2207. STAB *stab1;
  2208. STAB *stab2;
  2209. int *arglast;
  2210. {
  2211.     register STR **st = stack->ary_array;
  2212.     register int sp = arglast[2];
  2213.     register STIO *stio1;
  2214.     register STIO *stio2;
  2215.     int domain, type, protocol, fd[2];
  2216.  
  2217.  
  2218.     if (!stab1 || !stab2)
  2219.     return FALSE;
  2220.  
  2221.  
  2222.     stio1 = stab_io(stab1);
  2223.     stio2 = stab_io(stab2);
  2224.     if (!stio1)
  2225.     stio1 = stab_io(stab1) = stio_new();
  2226.     else if (stio1->ifp)
  2227.     do_close(stab1,FALSE);
  2228.     if (!stio2)
  2229.     stio2 = stab_io(stab2) = stio_new();
  2230.     else if (stio2->ifp)
  2231.     do_close(stab2,FALSE);
  2232.  
  2233.  
  2234.     domain = (int)str_gnum(st[++sp]);
  2235.     type = (int)str_gnum(st[++sp]);
  2236.     protocol = (int)str_gnum(st[++sp]);
  2237. #ifdef TAINT
  2238.     taintproper("Insecure dependency in socketpair");
  2239. #endif
  2240. #ifdef HAS_SOCKETPAIR
  2241.     if (socketpair(domain,type,protocol,fd) < 0)
  2242.     return FALSE;
  2243. #else
  2244.     fatal("Socketpair unimplemented");
  2245. #endif
  2246.     stio1->ifp = fdopen(fd[0], "r");
  2247.     stio1->ofp = fdopen(fd[0], "w");
  2248.     stio1->type = 's';
  2249.     stio2->ifp = fdopen(fd[1], "r");
  2250.     stio2->ofp = fdopen(fd[1], "w");
  2251.     stio2->type = 's';
  2252.     if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
  2253.     if (stio1->ifp) fclose(stio1->ifp);
  2254.     if (stio1->ofp) fclose(stio1->ofp);
  2255.     if (!stio1->ifp && !stio1->ofp) close(fd[0]);
  2256.     if (stio2->ifp) fclose(stio2->ifp);
  2257.     if (stio2->ofp) fclose(stio2->ofp);
  2258.     if (!stio2->ifp && !stio2->ofp) close(fd[1]);
  2259.     return FALSE;
  2260.     }
  2261.  
  2262.  
  2263.     return TRUE;
  2264. }
  2265.  
  2266.  
  2267. #endif /* HAS_SOCKET */
  2268.  
  2269.  
  2270. int
  2271. do_gpwent(which,gimme,arglast)
  2272. int which;
  2273. int gimme;
  2274. int *arglast;
  2275. {
  2276. #ifdef I_PWD
  2277.     register ARRAY *ary = stack;
  2278.     register int sp = arglast[0];
  2279.     register STR *str;
  2280.     struct passwd *getpwnam();
  2281.     struct passwd *getpwuid();
  2282.     struct passwd *getpwent();
  2283.     struct passwd *pwent;
  2284.  
  2285.  
  2286.     if (gimme != G_ARRAY) {
  2287.     astore(ary, ++sp, str_mortal(&str_undef));
  2288.     return sp;
  2289.     }
  2290.  
  2291.  
  2292.     if (which == O_GPWNAM) {
  2293.     char *name = str_get(ary->ary_array[sp+1]);
  2294.  
  2295.  
  2296.     pwent = getpwnam(name);
  2297.     }
  2298.     else if (which == O_GPWUID) {
  2299.     int uid = (int)str_gnum(ary->ary_array[sp+1]);
  2300.  
  2301.  
  2302.     pwent = getpwuid(uid);
  2303.     }
  2304.     else
  2305.     pwent = getpwent();
  2306.  
  2307.  
  2308.     if (pwent) {
  2309.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2310.     str_set(str, pwent->pw_name);
  2311.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2312.     str_set(str, pwent->pw_passwd);
  2313.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2314.     str_numset(str, (double)pwent->pw_uid);
  2315.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2316.     str_numset(str, (double)pwent->pw_gid);
  2317.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2318. #ifdef PWCHANGE
  2319.     str_numset(str, (double)pwent->pw_change);
  2320. #else
  2321. #ifdef PWQUOTA
  2322.     str_numset(str, (double)pwent->pw_quota);
  2323. #else
  2324. #ifdef PWAGE
  2325.     str_set(str, pwent->pw_age);
  2326. #endif
  2327. #endif
  2328. #endif
  2329.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2330. #ifdef PWCLASS
  2331.     str_set(str,pwent->pw_class);
  2332. #else
  2333. #ifdef PWCOMMENT
  2334.     str_set(str, pwent->pw_comment);
  2335. #endif
  2336. #endif
  2337.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2338.     str_set(str, pwent->pw_gecos);
  2339.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2340.     str_set(str, pwent->pw_dir);
  2341.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2342.     str_set(str, pwent->pw_shell);
  2343. #ifdef PWEXPIRE
  2344.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2345.     str_numset(str, (double)pwent->pw_expire);
  2346. #endif
  2347.     }
  2348.  
  2349.  
  2350.     return sp;
  2351. #else
  2352.     fatal("password routines not implemented");
  2353. #endif
  2354. }
  2355.  
  2356.  
  2357. int
  2358. do_ggrent(which,gimme,arglast)
  2359. int which;
  2360. int gimme;
  2361. int *arglast;
  2362. {
  2363. #ifdef I_GRP
  2364.     register ARRAY *ary = stack;
  2365.     register int sp = arglast[0];
  2366.     register char **elem;
  2367.     register STR *str;
  2368.     struct group *getgrnam();
  2369.     struct group *getgrgid();
  2370.     struct group *getgrent();
  2371.     struct group *grent;
  2372.  
  2373.  
  2374.     if (gimme != G_ARRAY) {
  2375.     astore(ary, ++sp, str_mortal(&str_undef));
  2376.     return sp;
  2377.     }
  2378.  
  2379.  
  2380.     if (which == O_GGRNAM) {
  2381.     char *name = str_get(ary->ary_array[sp+1]);
  2382.  
  2383.  
  2384.     grent = getgrnam(name);
  2385.     }
  2386.     else if (which == O_GGRGID) {
  2387.     int gid = (int)str_gnum(ary->ary_array[sp+1]);
  2388.  
  2389.  
  2390.     grent = getgrgid(gid);
  2391.     }
  2392.     else
  2393.     grent = getgrent();
  2394.  
  2395.  
  2396.     if (grent) {
  2397.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2398.     str_set(str, grent->gr_name);
  2399.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2400.     str_set(str, grent->gr_passwd);
  2401.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2402.     str_numset(str, (double)grent->gr_gid);
  2403.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2404.     for (elem = grent->gr_mem; *elem; elem++) {
  2405.         str_cat(str, *elem);
  2406.         if (elem[1])
  2407.         str_ncat(str," ",1);
  2408.     }
  2409.     }
  2410.  
  2411.  
  2412.     return sp;
  2413. #else
  2414.     fatal("group routines not implemented");
  2415. #endif
  2416. }
  2417.  
  2418.  
  2419. int
  2420. do_dirop(optype,stab,gimme,arglast)
  2421. int optype;
  2422. STAB *stab;
  2423. int gimme;
  2424. int *arglast;
  2425. {
  2426. #if defined(DIRENT) && defined(HAS_READDIR)
  2427.     register ARRAY *ary = stack;
  2428.     register STR **st = ary->ary_array;
  2429.     register int sp = arglast[1];
  2430.     register STIO *stio;
  2431.     long along;
  2432. #ifndef telldir
  2433.     long telldir();
  2434. #endif
  2435. #ifndef apollo
  2436.     struct DIRENT *readdir();
  2437. #endif
  2438.     register struct DIRENT *dp;
  2439.  
  2440.  
  2441.     if (!stab)
  2442.     goto nope;
  2443.     if (!(stio = stab_io(stab)))
  2444.     stio = stab_io(stab) = stio_new();
  2445.     if (!stio->dirp && optype != O_OPEN_DIR)
  2446.     goto nope;
  2447.     st[sp] = &str_yes;
  2448.     switch (optype) {
  2449.     case O_OPEN_DIR:
  2450.     if (stio->dirp)
  2451.         closedir(stio->dirp);
  2452.     if (!(stio->dirp = opendir(str_get(st[sp+1]))))
  2453.         goto nope;
  2454.     break;
  2455.     case O_READDIR:
  2456.     if (gimme == G_ARRAY) {
  2457.         --sp;
  2458.         /*SUPPRESS 560*/
  2459.         while (dp = readdir(stio->dirp)) {
  2460. #ifdef DIRNAMLEN
  2461.         (void)astore(ary,++sp,
  2462.           str_2mortal(str_make(dp->d_name,dp->d_namlen)));
  2463. #else
  2464.         (void)astore(ary,++sp,
  2465.           str_2mortal(str_make(dp->d_name,0)));
  2466. #endif
  2467.         }
  2468.     }
  2469.     else {
  2470.         if (!(dp = readdir(stio->dirp)))
  2471.         goto nope;
  2472.         st[sp] = str_mortal(&str_undef);
  2473. #ifdef DIRNAMLEN
  2474.         str_nset(st[sp], dp->d_name, dp->d_namlen);
  2475. #else
  2476.         str_set(st[sp], dp->d_name);
  2477. #endif
  2478.     }
  2479.     break;
  2480. #if MACH
  2481.     case O_TELLDIR:
  2482.     case O_SEEKDIR:
  2483.         goto nope;
  2484. #else
  2485.     case O_TELLDIR:
  2486.     st[sp] = str_mortal(&str_undef);
  2487.     str_numset(st[sp], (double)telldir(stio->dirp));
  2488.     break;
  2489.     case O_SEEKDIR:
  2490.     st[sp] = str_mortal(&str_undef);
  2491.     along = (long)str_gnum(st[sp+1]);
  2492.     (void)seekdir(stio->dirp,along);
  2493.     break;
  2494. #endif
  2495.     case O_REWINDDIR:
  2496.     st[sp] = str_mortal(&str_undef);
  2497.     (void)rewinddir(stio->dirp);
  2498.     break;
  2499.     case O_CLOSEDIR:
  2500.     st[sp] = str_mortal(&str_undef);
  2501.     (void)closedir(stio->dirp);
  2502.     stio->dirp = 0;
  2503.     break;
  2504.     }
  2505.     return sp;
  2506.  
  2507.  
  2508. nope:
  2509.     st[sp] = &str_undef;
  2510.     if (!errno)
  2511.     errno = EBADF;
  2512.     return sp;
  2513.  
  2514.  
  2515. #else
  2516.     fatal("Unimplemented directory operation");
  2517. #endif
  2518. }
  2519.  
  2520.  
  2521. apply(type,arglast)
  2522. int type;
  2523. int *arglast;
  2524. {
  2525.     register STR **st = stack->ary_array;
  2526.     register int sp = arglast[1];
  2527.     register int items = arglast[2] - sp;
  2528.     register int val;
  2529.     register int val2;
  2530.     register int tot = 0;
  2531.     char *s;
  2532.  
  2533.  
  2534. #ifdef TAINT
  2535.     for (st += ++sp; items--; st++)
  2536.     tainted |= (*st)->str_tainted;
  2537.     st = stack->ary_array;
  2538.     sp = arglast[1];
  2539.     items = arglast[2] - sp;
  2540. #endif
  2541.     switch (type) {
  2542.     case O_CHMOD:
  2543. #ifdef TAINT
  2544.     taintproper("Insecure dependency in chmod");
  2545. #endif
  2546.     if (--items > 0) {
  2547.         tot = items;
  2548.         val = (int)str_gnum(st[++sp]);
  2549.         while (items--) {
  2550.         if (chmod(str_get(st[++sp]),val))
  2551.             tot--;
  2552.         }
  2553.     }
  2554.     break;
  2555. #ifdef HAS_CHOWN
  2556.     case O_CHOWN:
  2557. #ifdef TAINT
  2558.     taintproper("Insecure dependency in chown");
  2559. #endif
  2560.     if (items > 2) {
  2561.         items -= 2;
  2562.         tot = items;
  2563.         val = (int)str_gnum(st[++sp]);
  2564.         val2 = (int)str_gnum(st[++sp]);
  2565.         while (items--) {
  2566.         if (chown(str_get(st[++sp]),val,val2))
  2567.             tot--;
  2568.         }
  2569.     }
  2570.     break;
  2571. #endif
  2572. #ifdef HAS_KILL
  2573.     case O_KILL:
  2574. #ifdef TAINT
  2575.     taintproper("Insecure dependency in kill");
  2576. #endif
  2577.     if (--items > 0) {
  2578.         tot = items;
  2579.         s = str_get(st[++sp]);
  2580.         if (isUPPER(*s)) {
  2581.         if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
  2582.             s += 3;
  2583.         if (!(val = whichsig(s)))
  2584.             fatal("Unrecognized signal name \"%s\"",s);
  2585.         }
  2586.         else
  2587.         val = (int)str_gnum(st[sp]);
  2588.         if (val < 0) {
  2589.         val = -val;
  2590.         while (items--) {
  2591.             int proc = (int)str_gnum(st[++sp]);
  2592. #ifdef HAS_KILLPG
  2593.             if (killpg(proc,val))    /* BSD */
  2594. #else
  2595.             if (kill(-proc,val))    /* SYSV */
  2596. #endif
  2597.             tot--;
  2598.         }
  2599.         }
  2600.         else {
  2601.         while (items--) {
  2602.             if (kill((int)(str_gnum(st[++sp])),val))
  2603.             tot--;
  2604.         }
  2605.         }
  2606.     }
  2607.     break;
  2608. #endif
  2609.     case O_UNLINK:
  2610. #ifdef TAINT
  2611.     taintproper("Insecure dependency in unlink");
  2612. #endif
  2613.     tot = items;
  2614.     while (items--) {
  2615.         s = str_get(st[++sp]);
  2616.         if (euid || unsafe) {
  2617.         if (UNLINK(s))
  2618.             tot--;
  2619.         }
  2620.         else {    /* don't let root wipe out directories without -U */
  2621. #ifdef HAS_LSTAT
  2622.         if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2623. #else
  2624.         if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2625. #endif
  2626.             tot--;
  2627.         else {
  2628.             if (UNLINK(s))
  2629.             tot--;
  2630.         }
  2631.         }
  2632.     }
  2633.     break;
  2634.     case O_UTIME:
  2635. #ifdef TAINT
  2636.     taintproper("Insecure dependency in utime");
  2637. #endif
  2638.     if (items > 2) {
  2639. #ifdef I_UTIME
  2640.         struct utimbuf utbuf;
  2641. #else
  2642.         struct {
  2643.         long    actime;
  2644.         long    modtime;
  2645.         } utbuf;
  2646. #endif
  2647.  
  2648.  
  2649.         Zero(&utbuf, sizeof utbuf, char);
  2650.         utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
  2651.         utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
  2652.         items -= 2;
  2653. #ifndef lint
  2654.         tot = items;
  2655.         while (items--) {
  2656.         if (utime(str_get(st[++sp]),&utbuf))
  2657.             tot--;
  2658.         }
  2659. #endif
  2660.     }
  2661.     else
  2662.         items = 0;
  2663.     break;
  2664.     }
  2665.     return tot;
  2666. }
  2667.  
  2668.  
  2669. /* Do the permissions allow some operation?  Assumes statcache already set. */
  2670.  
  2671.  
  2672. int
  2673. cando(bit, effective, statbufp)
  2674. int bit;
  2675. int effective;
  2676. register struct stat *statbufp;
  2677. {
  2678. #ifdef MSDOS
  2679.     /* [Comments and code from Len Reed]
  2680.      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
  2681.      * to write-protected files.  The execute permission bit is set
  2682.      * by the Miscrosoft C library stat() function for the following:
  2683.      *        .exe files
  2684.      *        .com files
  2685.      *        .bat files
  2686.      *        directories
  2687.      * All files and directories are readable.
  2688.      * Directories and special files, e.g. "CON", cannot be
  2689.      * write-protected.
  2690.      * [Comment by Tom Dinger -- a directory can have the write-protect
  2691.      *        bit set in the file system, but DOS permits changes to
  2692.      *        the directory anyway.  In addition, all bets are off
  2693.      *        here for networked software, such as Novell and
  2694.      *        Sun's PC-NFS.]
  2695.      */
  2696.  
  2697.  
  2698.      return (bit & statbufp->st_mode) ? TRUE : FALSE;
  2699.  
  2700.  
  2701. #else /* ! MSDOS */
  2702.     if ((effective ? euid : uid) == 0) {    /* root is special */
  2703.     if (bit == S_IXUSR) {
  2704.         if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
  2705.         return TRUE;
  2706.     }
  2707.     else
  2708.         return TRUE;        /* root reads and writes anything */
  2709.     return FALSE;
  2710.     }
  2711.     if (statbufp->st_uid == (effective ? euid : uid) ) {
  2712.     if (statbufp->st_mode & bit)
  2713.         return TRUE;    /* ok as "user" */
  2714.     }
  2715.     else if (ingroup((int)statbufp->st_gid,effective)) {
  2716.     if (statbufp->st_mode & bit >> 3)
  2717.         return TRUE;    /* ok as "group" */
  2718.     }
  2719.     else if (statbufp->st_mode & bit >> 6)
  2720.     return TRUE;    /* ok as "other" */
  2721.     return FALSE;
  2722. #endif /* ! MSDOS */
  2723. }
  2724.  
  2725.  
  2726. int
  2727. ingroup(testgid,effective)
  2728. int testgid;
  2729. int effective;
  2730. {
  2731.     if (testgid == (effective ? egid : gid))
  2732.     return TRUE;
  2733. #ifdef HAS_GETGROUPS
  2734. #ifndef NGROUPS
  2735. #define NGROUPS 32
  2736. #endif
  2737.     {
  2738.     GROUPSTYPE gary[NGROUPS];
  2739.     int anum;
  2740.  
  2741.  
  2742.     anum = getgroups(NGROUPS,gary);
  2743.     while (--anum >= 0)
  2744.         if (gary[anum] == testgid)
  2745.         return TRUE;
  2746.     }
  2747. #endif
  2748.     return FALSE;
  2749. }
  2750.  
  2751.  
  2752. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  2753.  
  2754.  
  2755. int
  2756. do_ipcget(optype, arglast)
  2757. int optype;
  2758. int *arglast;
  2759. {
  2760.     register STR **st = stack->ary_array;
  2761.     register int sp = arglast[0];
  2762.     key_t key;
  2763.     int n, flags;
  2764.  
  2765.  
  2766.     key = (key_t)str_gnum(st[++sp]);
  2767.     n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
  2768.     flags = (int)str_gnum(st[++sp]);
  2769.     errno = 0;
  2770.     switch (optype)
  2771.     {
  2772. #ifdef HAS_MSG
  2773.     case O_MSGGET:
  2774.     return msgget(key, flags);
  2775. #endif
  2776. #ifdef HAS_SEM
  2777.     case O_SEMGET:
  2778.     return semget(key, n, flags);
  2779. #endif
  2780. #ifdef HAS_SHM
  2781.     case O_SHMGET:
  2782.     return shmget(key, n, flags);
  2783. #endif
  2784. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2785.     default:
  2786.     fatal("%s not implemented", opname[optype]);
  2787. #endif
  2788.     }
  2789.     return -1;            /* should never happen */
  2790. }
  2791.  
  2792.  
  2793. int
  2794. do_ipcctl(optype, arglast)
  2795. int optype;
  2796. int *arglast;
  2797. {
  2798.     register STR **st = stack->ary_array;
  2799.     register int sp = arglast[0];
  2800.     STR *astr;
  2801.     char *a;
  2802.     int id, n, cmd, infosize, getinfo, ret;
  2803.  
  2804.  
  2805.     id = (int)str_gnum(st[++sp]);
  2806.     n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
  2807.     cmd = (int)str_gnum(st[++sp]);
  2808.     astr = st[++sp];
  2809.  
  2810.  
  2811.     infosize = 0;
  2812.     getinfo = (cmd == IPC_STAT);
  2813.  
  2814.  
  2815.     switch (optype)
  2816.     {
  2817. #ifdef HAS_MSG
  2818.     case O_MSGCTL:
  2819.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2820.         infosize = sizeof(struct msqid_ds);
  2821.     break;
  2822. #endif
  2823. #ifdef HAS_SHM
  2824.     case O_SHMCTL:
  2825.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2826.         infosize = sizeof(struct shmid_ds);
  2827.     break;
  2828. #endif
  2829. #ifdef HAS_SEM
  2830.     case O_SEMCTL:
  2831.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2832.         infosize = sizeof(struct semid_ds);
  2833.     else if (cmd == GETALL || cmd == SETALL)
  2834.     {
  2835.         struct semid_ds semds;
  2836.         if (semctl(id, 0, IPC_STAT, &semds) == -1)
  2837.         return -1;
  2838.         getinfo = (cmd == GETALL);
  2839.         infosize = semds.sem_nsems * sizeof(short);
  2840.         /* "short" is technically wrong but much more portable
  2841.            than guessing about u_?short(_t)? */
  2842.     }
  2843.     break;
  2844. #endif
  2845. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2846.     default:
  2847.     fatal("%s not implemented", opname[optype]);
  2848. #endif
  2849.     }
  2850.  
  2851.  
  2852.     if (infosize)
  2853.     {
  2854.     if (getinfo)
  2855.     {
  2856.         STR_GROW(astr, infosize+1);
  2857.         a = str_get(astr);
  2858.     }
  2859.     else
  2860.     {
  2861.         a = str_get(astr);
  2862.         if (astr->str_cur != infosize)
  2863.         {
  2864.         errno = EINVAL;
  2865.         return -1;
  2866.         }
  2867.     }
  2868.     }
  2869.     else
  2870.     {
  2871.     int i = (int)str_gnum(astr);
  2872.     a = (char *)i;        /* ouch */
  2873.     }
  2874.     errno = 0;
  2875.     switch (optype)
  2876.     {
  2877. #ifdef HAS_MSG
  2878.     case O_MSGCTL:
  2879.     ret = msgctl(id, cmd, a);
  2880.     break;
  2881. #endif
  2882. #ifdef HAS_SEM
  2883.     case O_SEMCTL:
  2884.     ret = semctl(id, n, cmd, a);
  2885.     break;
  2886. #endif
  2887. #ifdef HAS_SHM
  2888.     case O_SHMCTL:
  2889.     ret = shmctl(id, cmd, a);
  2890.     break;
  2891. #endif
  2892.     }
  2893.     if (getinfo && ret >= 0) {
  2894.     astr->str_cur = infosize;
  2895.     astr->str_ptr[infosize] = '\0';
  2896.     }
  2897.     return ret;
  2898. }
  2899.  
  2900.  
  2901. int
  2902. do_msgsnd(arglast)
  2903. int *arglast;
  2904. {
  2905. #ifdef HAS_MSG
  2906.     register STR **st = stack->ary_array;
  2907.     register int sp = arglast[0];
  2908.     STR *mstr;
  2909.     char *mbuf;
  2910.     int id, msize, flags;
  2911.  
  2912.  
  2913.     id = (int)str_gnum(st[++sp]);
  2914.     mstr = st[++sp];
  2915.     flags = (int)str_gnum(st[++sp]);
  2916.     mbuf = str_get(mstr);
  2917.     if ((msize = mstr->str_cur - sizeof(long)) < 0) {
  2918.     errno = EINVAL;
  2919.     return -1;
  2920.     }
  2921.     errno = 0;
  2922.     return msgsnd(id, mbuf, msize, flags);
  2923. #else
  2924.     fatal("msgsnd not implemented");
  2925. #endif
  2926. }
  2927.  
  2928.  
  2929. int
  2930. do_msgrcv(arglast)
  2931. int *arglast;
  2932. {
  2933. #ifdef HAS_MSG
  2934.     register STR **st = stack->ary_array;
  2935.     register int sp = arglast[0];
  2936.     STR *mstr;
  2937.     char *mbuf;
  2938.     long mtype;
  2939.     int id, msize, flags, ret;
  2940.  
  2941.  
  2942.     id = (int)str_gnum(st[++sp]);
  2943.     mstr = st[++sp];
  2944.     msize = (int)str_gnum(st[++sp]);
  2945.     mtype = (long)str_gnum(st[++sp]);
  2946.     flags = (int)str_gnum(st[++sp]);
  2947.     mbuf = str_get(mstr);
  2948.     if (mstr->str_cur < sizeof(long)+msize+1) {
  2949.     STR_GROW(mstr, sizeof(long)+msize+1);
  2950.     mbuf = str_get(mstr);
  2951.     }
  2952.     errno = 0;
  2953.     ret = msgrcv(id, mbuf, msize, mtype, flags);
  2954.     if (ret >= 0) {
  2955.     mstr->str_cur = sizeof(long)+ret;
  2956.     mstr->str_ptr[sizeof(long)+ret] = '\0';
  2957.     }
  2958.     return ret;
  2959. #else
  2960.     fatal("msgrcv not implemented");
  2961. #endif
  2962. }
  2963.  
  2964.  
  2965. int
  2966. do_semop(arglast)
  2967. int *arglast;
  2968. {
  2969. #ifdef HAS_SEM
  2970.     register STR **st = stack->ary_array;
  2971.     register int sp = arglast[0];
  2972.     STR *opstr;
  2973.     char *opbuf;
  2974.     int id, opsize;
  2975.  
  2976.  
  2977.     id = (int)str_gnum(st[++sp]);
  2978.     opstr = st[++sp];
  2979.     opbuf = str_get(opstr);
  2980.     opsize = opstr->str_cur;
  2981.     if (opsize < sizeof(struct sembuf)
  2982.     || (opsize % sizeof(struct sembuf)) != 0) {
  2983.     errno = EINVAL;
  2984.     return -1;
  2985.     }
  2986.     errno = 0;
  2987.     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
  2988. #else
  2989.     fatal("semop not implemented");
  2990. #endif
  2991. }
  2992.  
  2993.  
  2994. int
  2995. do_shmio(optype, arglast)
  2996. int optype;
  2997. int *arglast;
  2998. {
  2999. #ifdef HAS_SHM
  3000.     register STR **st = stack->ary_array;
  3001.     register int sp = arglast[0];
  3002.     STR *mstr;
  3003.     char *mbuf, *shm;
  3004.     int id, mpos, msize;
  3005.     struct shmid_ds shmds;
  3006. #ifndef VOIDSHMAT
  3007.     extern char *shmat();
  3008. #endif
  3009.  
  3010.  
  3011.     id = (int)str_gnum(st[++sp]);
  3012.     mstr = st[++sp];
  3013.     mpos = (int)str_gnum(st[++sp]);
  3014.     msize = (int)str_gnum(st[++sp]);
  3015.     errno = 0;
  3016.     if (shmctl(id, IPC_STAT, &shmds) == -1)
  3017.     return -1;
  3018.     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
  3019.     errno = EFAULT;        /* can't do as caller requested */
  3020.     return -1;
  3021.     }
  3022.     shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
  3023.     if (shm == (char *)-1)    /* I hate System V IPC, I really do */
  3024.     return -1;
  3025.     mbuf = str_get(mstr);
  3026.     if (optype == O_SHMREAD) {
  3027.     if (mstr->str_cur < msize) {
  3028.         STR_GROW(mstr, msize+1);
  3029.         mbuf = str_get(mstr);
  3030.     }
  3031.     bcopy(shm + mpos, mbuf, msize);
  3032.     mstr->str_cur = msize;
  3033.     mstr->str_ptr[msize] = '\0';
  3034.     }
  3035.     else {
  3036.     int n;
  3037.  
  3038.  
  3039.     if ((n = mstr->str_cur) > msize)
  3040.         n = msize;
  3041.     bcopy(mbuf, shm + mpos, n);
  3042.     if (n < msize)
  3043.         bzero(shm + mpos + n, msize - n);
  3044.     }
  3045.     return shmdt(shm);
  3046. #else
  3047.     fatal("shm I/O not implemented");
  3048. #endif
  3049. }
  3050.  
  3051.  
  3052. #endif /* SYSV IPC */
  3053.